package com.study.nvr.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.study.config.RedisUtil;
import com.study.nvr.bean.CmdTasker;
import com.study.nvr.service.NvrService;
import com.study.utils.SysUtils;
import lombok.extern.slf4j.Slf4j;
import nvr.utils.ConfigUtils;
import nvr.utils.NvrUtils;
import nvr.utils.commandManager.CommandManager;
import nvr.utils.commandManager.data.CommandTasker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author study
 * @version 1.0
 * @date 2020/6/15 23:30
 */
@Slf4j
@Service
public class NvrServiceImpl implements NvrService {

    @Value("${nvr.screen.snap}")
    private String snapOrder;

    /**
     * 录制屏幕
     */
    @Value("${nvr.screen.record}")
    String screenOrder;
    @Value("${nvr.save.localpath}")
    String screenPath;
    @Autowired
    CommandManager commandManager;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RedisUtil redisUtil;

    @Override
    public void recordScreen() {

    }

    @Override
    public String snap() {
        String snap = NvrUtils.getResourcePath("snap");
        String date = SysUtils.getDate4();

        log.info("命令ID{} 存储路径{}", date, snap);
        commandManager.start(String.format(ConfigUtils.FFMPEG_CMD_SNAP, date),
                String.format(snapOrder, snap, date)
        );
        return String.format("%s/%s.jpg", snap, date);
    }

    @Override
    public ArrayList<CmdTasker> getTasks() {
        Collection<CommandTasker> taskers = commandManager.queryAll();
        //TODO java8 stream 取出对象中某个字段
        ArrayList<CmdTasker> cmdTaskers = new ArrayList<>();


        for (CommandTasker tasker : taskers) {
            tasker.getCommand();
            cmdTaskers.add(new CmdTasker()//
                    .setCommand(tasker.getCommand())//
                    .setId(tasker.getId()).setProcess(tasker.getProcess().isAlive())//
                    .setThread(tasker.getThread().isAlive()));
        }
        return cmdTaskers;
    }

    @Override
    public String screen() {
        String date = SysUtils.getDate4();
        log.info("命令ID{} ", date);
        commandManager.start(String.format(ConfigUtils.FFMPEG_CMD_ID, date), screenOrder);
        return screenPath;
    }


    /**
     * 从Redis中取出 存储信息并按照各个节点分组
     *
     * @return 各个节点分组 的流信息
     */
    private Map<String, List<CmdTasker>> getRedisTask() {
        try {
            List<String> redis = redisTemplate.opsForHash().values(ConfigUtils.REDIS_HASH_KEY);
            List<CmdTasker> result = new ArrayList<>();
            for (String value : redis) {
                result.add(JSONObject.parseObject(value, CmdTasker.class));
            }
            //分组 key;使用key取出 本机的 推流信息
            return result.stream().collect(Collectors.groupingBy(CmdTasker::getRemoteAddr));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 执行请求停止 ffmpeg命令，如果请求没有响应，认为该节点宕机，删除Redis中该节点的推流信息
     *
     * @param taskId ffmepg任务ID
     * @return 返回停止结果
     */
    private boolean remoteStopById(String taskId) {
        String ffmpegTaskStr = (String) redisUtil.hget(ConfigUtils.REDIS_HASH_KEY, taskId.replace("stream_", ""));
        CmdTasker task = JSONObject.parseObject(ffmpegTaskStr, CmdTasker.class);
        if (task != null) {
            try {
                // httpGet(ConfigUtils.REMOTE_TYPE_STOP, task.getRemoteAddr(), null);
            } catch (Exception e) {
                log.info("请求{}停止推流 响应失败，疑似该节点宕机，删除该节点所有Redis中的推流信息", task.getRemoteAddr());
                delRedisTaskInfo(task.getRemoteAddr());
            }
        }
        return true;
    }

    /**
     * 删除Redis中推流信息
     *
     * @param key 删除的分组信息
     */
    private void delRedisTaskInfo(String key) {
        Map<String, List<CmdTasker>> collect = getRedisTask();
        if (collect != null) {
            List<CmdTasker> CmdTaskers = collect.get(key);
            if (CmdTaskers != null && !CmdTaskers.isEmpty()) {
                List<String> ids = CmdTaskers.stream().map(CmdTasker::getId).collect(Collectors.toList());
                redisTemplate.opsForHash().delete(ConfigUtils.REDIS_HASH_KEY, ids.toArray());
            }
        }
    }
}
